/*
https://en.cppreference.com/w/cpp/thread/unique_lock

std::mutex::lock:  
https://en.cppreference.com/w/cpp/thread/mutex/lock



//mark: TEST
*/

#include <mutex>
#include <thread>
#include <chrono>
#include <iostream>
#include <unistd.h>

#include <stdio.h>1
using namespace std;

struct Box
{
    explicit Box(int num)
        : num_things{num}
    {
    }

    int num_things;
    std::mutex m;
};

void transfer(Box &from, Box &to, int num, int id)
{
    //sleep(1);
    // don't actually take the locks yet

    // std::unique_lock<std::mutex> lock1(from.m, std::defer_lock);
    // std::unique_lock<std::mutex> lock2(to.m, std::defer_lock);

    // lock both unique_locks without deadlock

    //  std::lock(lock1, lock2);
    printf("line:%d by id:[%d\n", __LINE__, id);
    to.m.lock();
    printf("line:%d by id:[%d\n", __LINE__, id);
    //from.m.lock();
    printf("line:%d by id:[%d\n", __LINE__, id);

    // /  std::lock(from.m,to.m);
    printf("line:%d by id:[%d\n", __LINE__, id);
    from.num_things -= num;
    printf("line:%d by id:[%d\n", __LINE__, id);
    to.num_things += num;
    printf("line:%d by id:[%d\n", __LINE__, id);
    // 'from.m' and 'to.m' mutexes unlocked in 'unique_lock' dtors
    printf("\n[id]:%d [from.num_things]:%d\n", id, from.num_things);
    printf("[id]:%d [to.num_things]:%d\n", id, to.num_things);
    // from.m.unlock();
    // to.m.unlock();
}

int main()
{
    cout << "1111<<" << endl;
    Box acc1(100);
    Box acc2(50);

    std::thread t1(transfer, std::ref(acc1), std::ref(acc2), 10, 1);
    std::thread t2(transfer, std::ref(acc2), std::ref(acc1), 5, 2);
    std::thread t3(transfer, std::ref(acc1), std::ref(acc2), 10, 3);
    t1.join();
    t2.join();
    t3.join();
    // while(1)
    // {
    //   printf("%d\n",__LINE__);
    // }

    cout
        << "\nacc1.num_things: " << acc1.num_things << endl;
    cout << "acc2.num_things: " << acc2.num_things << endl;
}
